package be.dch.gui.panels;

import java.awt.Color;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.HashMap;
import java.util.Map;

import javax.swing.BorderFactory;
import javax.swing.Icon;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JPanel;

import org.apache.log4j.Logger;

import be.dch.exceptions.InvalidParameterException;
import be.dch.gui.SwingUtils;
import be.dch.gui.components.JAddPoint;
import be.dch.gui.layout.RegexFileFilter;
import be.dch.typeditor.TypEditor;
import be.dch.typeditor.domain.GarminIcon;

import com.jgoodies.forms.builder.PanelBuilder;
import com.jgoodies.forms.layout.CellConstraints;
import com.jgoodies.forms.layout.FormLayout;

public final class TypEditorPanel extends AbstractPanel implements ActionListener, PropertyChangeListener {

    /** * */
    private static final long serialVersionUID = 7413135296425430669L;
    private static final Logger LOG = Logger.getLogger(TypEditorPanel.class);
    private static final String CMD_OPEN = "open";
    private static final String CMD_SAVE = "save";
    private static final String CMD_NEW = "new";

    // TODO columnSpecs
    // 1 2 3 4 5 6 7 8 9 10 11 12
    // jap O S N
    private static final String COLUMN_SPECS = "3dlu,pref,3dlu,pref:grow,3dlu,pref,3dlu,pref,3dlu,pref,3dlu";
    private static final String ROW_SPECS = "3dlu,pref,3dlu,pref,3dlu,pref,3dlu,pref,3dlu,pref,3dlu,pref:grow";

    private static TypEditorPanel instance = new TypEditorPanel();
    private final transient TypEditor editor;
    private final transient JAddPoint japPois;
    private final transient JAddPoint japPolyglons;
    private final transient JAddPoint japPolylines;
    private final transient TypEditorListPanel listPanel;
    private final transient TypEditorDetailPanel detailPanel;
    private final transient Map<String, JPanel> cards = new HashMap<String, JPanel>();;

    private TypEditorPanel() {
	super();
	final FormLayout layout = new FormLayout(TypEditorPanel.COLUMN_SPECS, TypEditorPanel.ROW_SPECS);
	final CellConstraints constraints = new CellConstraints();
	final PanelBuilder builder = new PanelBuilder(layout);

	final JButton btnOpen = new JButton("O");
	btnOpen.addActionListener(this);
	btnOpen.setActionCommand(TypEditorPanel.CMD_OPEN);
	final JButton btnSave = new JButton("S");
	btnSave.addActionListener(this);
	btnSave.setActionCommand(TypEditorPanel.CMD_SAVE);
	final JButton btnNew = new JButton("N");
	btnNew.addActionListener(this);
	btnNew.setActionCommand(TypEditorPanel.CMD_NEW);
	builder.add(btnOpen, constraints.rchw(2, 6, 1, 1));
	builder.add(btnSave, constraints.rchw(2, 8, 1, 1));
	builder.add(btnNew, constraints.rchw(2, 10, 1, 1));

	this.japPois = new JAddPoint("POI", TypEditor.POIS);
	this.japPois.addActionListener(this);
	this.japPois.addMouseListener(new MouseAdapter() {
	    @Override
	    public void mouseClicked(final MouseEvent event) {
		TypEditorPanel.this.selectJAddPoint(TypEditor.POIS);
	    }
	});
	this.japPolyglons = new JAddPoint("Polyglons", TypEditor.POLYGLONS);
	this.japPolyglons.addActionListener(this);
	this.japPolyglons.addMouseListener(new MouseAdapter() {
	    @Override
	    public void mouseClicked(final MouseEvent event) {
		TypEditorPanel.this.selectJAddPoint(TypEditor.POLYGLONS);
	    }
	});
	this.japPolylines = new JAddPoint("Polylines", TypEditor.POLYLINES);
	this.japPolylines.addActionListener(this);
	this.japPolylines.addMouseListener(new MouseAdapter() {

	    @Override
	    public void mouseClicked(final MouseEvent event) {
		TypEditorPanel.this.selectJAddPoint(TypEditor.POLYLINES);
	    }
	});
	this.japPois.addMouseListener(new MouseAdapter() {
	    @Override
	    public void mouseClicked(final MouseEvent event) {
		TypEditorPanel.this.selectJAddPoint(TypEditor.POIS);
	    }
	});
	builder.add(this.japPois, constraints.rchw(4, 2, 1, 1));
	builder.add(this.japPolyglons, constraints.rchw(6, 2, 1, 1));
	builder.add(this.japPolylines, constraints.rchw(8, 2, 1, 1));

	this.editor = new TypEditor();
	this.detailPanel = new TypEditorDetailPanel();
	final JPanel imagePanel = new TypEditorImagePanel();
	this.listPanel = new TypEditorListPanel(540, 500);
	this.listPanel.addPropertyChangeListener(this);

	// FIXME align to top
	final JPanel multiPanel = new JPanel();
	multiPanel.setBorder(BorderFactory.createLineBorder(Color.black));
	SwingUtils.setFixedDimensions(multiPanel, 540, 500);
	this.addToPanel(multiPanel, imagePanel);
	this.addToPanel(multiPanel, this.detailPanel);
	this.addToPanel(multiPanel, this.listPanel);
	this.flipToPage(this.listPanel.getClass());
	builder.add(multiPanel, constraints.rchw(4, 4, 9, 7));
	this.add(builder.getPanel());

    }

    public static TypEditorPanel getInstance() {
	return TypEditorPanel.instance;
    }

    @Override
    public String getPanelTitle() {
	return "Typ Editor";
    }

    @Override
    public Icon getPanelIcon() {
	return this.createImageIcon("/images/file-typeditor-icon.gif", "Main");
    }

    public void actionPerformed(final ActionEvent evt) {
	if (evt.getActionCommand() == TypEditorPanel.CMD_OPEN) {
	    final JFileChooser chooser = new JFileChooser();
	    chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
	    // TODO description of filter.
	    chooser.setFileFilter(new RegexFileFilter(".*.type", ""));
	    final int result = chooser.showOpenDialog(this);
	    if (result == 0) {
		this.editor.loadFile(chooser.getSelectedFile());
		this.japPois.initItem(this.editor.getPois().length);
		this.japPolyglons.initItem(this.editor.getPolyglons().length);
		this.japPolylines.initItem(this.editor.getPolylines().length);
		this.flipToPage(this.listPanel.getClass());

	    }
	} else if (evt.getActionCommand() == TypEditorPanel.CMD_SAVE) {
	    final JFileChooser chooser = new JFileChooser();
	    chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
	    // TODO description of filter.
	    chooser.setFileFilter(new RegexFileFilter(".*.type", ""));
	    final int result = chooser.showOpenDialog(this);
	    if (result == 0) {
		this.editor.saveFile(chooser.getSelectedFile());
		this.flipToPage(this.listPanel.getClass());

	    }
	} else if (evt.getActionCommand() == TypEditorPanel.CMD_NEW) {
	    this.editor.newFile();
	    this.listPanel.resetAllElements();
	    this.flipToPage(this.listPanel.getClass());
	    this.japPois.initItem(this.editor.getPois().length);
	    this.japPolyglons.initItem(this.editor.getPolyglons().length);
	    this.japPolylines.initItem(this.editor.getPolylines().length);

	} else if (evt.getActionCommand() == JAddPoint.CMD_ADD) {
	    final JButton but = (JButton) evt.getSource();
	    final int selected = Integer.parseInt(but.getName());
	    this.deSelectOtherJAddPoints(selected);
	    this.detailPanel.setGarminIcon(null);
	    this.flipToPage(TypEditorDetailPanel.class);
	}

    }

    /**
     * Updates the MainDialog with the panel with the given class name in its
     * card layout, and updates the title and descriptions in the MainDialog's
     * DialogHeader with values that correspond to the new panel., Feedback
     * messages are cleared from screen.
     * 
     * @param clazz
     */
    private void flipToPage(@SuppressWarnings("rawtypes") final Class clazz) {
	TypEditorPanel.LOG.info("flip to page " + clazz.getSimpleName());
	for (final JPanel panel : this.cards.values()) {
	    panel.setVisible(false);
	}
	final JPanel panel = this.cards.get(clazz.getSimpleName());
	panel.setVisible(true);
    }

    private void selectJAddPoint(final Integer selected) {
	this.deSelectOtherJAddPoints(selected);
	if ((selected == TypEditor.POIS) && !this.japPois.isSelected()) {
	    this.japPois.setSelected(true);
	} else if (selected == TypEditor.POLYGLONS) {
	    this.japPolyglons.setSelected(true);
	} else if (selected == TypEditor.POLYLINES) {
	    this.japPolylines.setSelected(true);
	}
	this.loadGarminIconArray(selected);
	this.flipToPage(TypEditorListPanel.class);

    }

    private void deSelectOtherJAddPoints(final Integer selected) {
	switch (selected) {
	case TypEditor.POLYLINES:
	    this.japPois.setSelected(false);
	    this.japPolyglons.setSelected(false);
	    break;
	case TypEditor.POIS:
	    this.japPolyglons.setSelected(false);
	    this.japPolylines.setSelected(false);
	    break;
	case TypEditor.POLYGLONS:
	    this.japPois.setSelected(false);
	    this.japPolylines.setSelected(false);
	    break;
	default:
	    break;
	}
	this.japPolyglons.setSelected(false);
    }

    private void loadGarminIconArray(final int selected) {
	try {
	    this.listPanel.setAllElements(this.editor.setSelectedAndGetGarminIconArray(selected));
	} catch (final InvalidParameterException ex) {
	    TypEditorPanel.LOG.error(ex);
	}
    }

    private void addToPanel(final JPanel container, final JPanel page) {

	if (container.getLayout() instanceof GridBagLayout) {
	    final GridBagConstraints constraints = new GridBagConstraints();
	    constraints.gridx = 0;
	    constraints.gridy = 0;
	    constraints.anchor = GridBagConstraints.NORTH;
	    constraints.insets = new Insets(0, 0, 0, 0);
	    ((GridBagLayout) container.getLayout()).setConstraints(page, constraints);
	}
	SwingUtils.setFixedDimensions(page, container.getWidth(), container.getHeight());
	this.cards.put(page.getClass().getSimpleName(), page);
	page.setVisible(false);
	container.add(page);
    }

    public void propertyChange(final PropertyChangeEvent evt) {
	if (evt.getPropertyName().equalsIgnoreCase(TypEditorListPanel.ITEM_SELECTED)) {
	    this.detailPanel.setGarminIcon((GarminIcon) evt.getNewValue());
	    this.flipToPage(this.detailPanel.getClass());
	}

    }
}
